package web_report

import (
	"bytes"
	"encoding/json"
	"fmt"
	"math/rand"
	"peilian-api/app/global/databases/tables"
	"peilian-api/app/global/log"
	"peilian-api/app/global/variable"
	"peilian-api/app/model"
	"strconv"
	"strings"
	"text/template"
)

type SlotValue struct {
	CareerName    string
	NegLabels     string
	AnswerContent string
}

type DefaultWebReport struct {
	*ReportData
	analyzeLabelsList []string
}

func (w *DefaultWebReport) GetTotalScore() float64 {
	total := w.avgLanguageScore*0.2 + w.avgThemeScore*0.3 + w.evaluateResp.EvalScore*100*0.5
	if total < 93 {
		total += w.logicScoreCache.Avg * 0.07
	}
	return total
}

func (w *DefaultWebReport) GetPosGeneralData() []LabelValue {
	chartsData := make([]LabelValue, 0)
	if w.evaluateResp.PosWordScore.General != nil {
		for _, pos := range w.evaluateResp.PosWordScore.General {
			score := 60 + int(pos[1].(float64)*100*25/100)
			score += rand.Intn(10) + 1
			chartsData = append(chartsData, LabelValue{
				Label: pos[0].(string),
				Value: score,
			})
		}
	}
	return chartsData
}

func (w *DefaultWebReport) GetNegGeneralData() []LabelValue {
	chartsData := make([]LabelValue, 0)
	if w.evaluateResp.NegScoreDict.General != nil {
		for _, neg := range w.evaluateResp.NegScoreDict.General {
			score := int(neg[1].(float64) * 100 * 30 / 100)
			chartsData = append(chartsData, LabelValue{
				Label: neg[0].(string),
				Value: score,
			})
		}
	}
	return chartsData
}
func (w *DefaultWebReport) GetGeneralData() *ScoreChart {
	chartsData := make([]LabelValue, 0)
	chartsData = append(chartsData, w.GetPosGeneralData()...)
	chartsData = append(chartsData, w.GetNegGeneralData()...)
	return &ScoreChart{
		Score:     int(w.evaluateResp.LabelScore.General * 100),
		ChartData: chartsData,
	}
}

func (w *DefaultWebReport) SetEvaluateResp(e model.LabelEvaluate) {
	w.ReportData.evaluateResp = &e
}

func (w *DefaultWebReport) GetSlotValueObj() *SlotValue {
	negLabels := make([]string, 0)
	for _, negLabel := range w.GetNegProfessionalData() {
		negLabels = append(negLabels, negLabel.Label)
	}
	return &SlotValue{
		CareerName:    w.Session.CareerName,
		NegLabels:     strings.Join(negLabels, "]["),
		AnswerContent: w.allAnswerContent,
	}
}

func (w *DefaultWebReport) GetSlotTemplate(slotValue *SlotValue) (string, error) {
	tempStr := "你现在是一个专业面试官，招聘岗位是[{{.CareerName}}]，同学的待提升能力为[{{.NegLabels}}]，" +
		"请分析同学的面试记录并输出在能力展现上的不足之处，" +
		"并输出对同学提升能力的面试指导，内容丰富深入。//输出格式：针对面试记录的分析和指导：\\n''" +
		"//其他要求：1.只输出面试指导，不输出面试记录和问候语。" +
		"2.避免重复内容。3.用简体中文输出。4.不超过600字符。//面试记录如下：[{{.AnswerContent}}]"
	temp, err := template.New("interview guide").Parse(tempStr)
	if err != nil {
		return "", err
	}
	var buffer bytes.Buffer
	if err := temp.Execute(&buffer, slotValue); err != nil {
		return "", err
	}
	filledStr := buffer.String()
	return filledStr, nil
}

func (w *DefaultWebReport) GetGlm2Guide() (interface{}, error) {
	prompt, err := w.GetSlotTemplate(w.IWebReport.GetSlotValueObj())
	if err != nil {
		return nil, err
	}
	req := map[string]string{"prompt": prompt}
	log.Logger.Info(fmt.Sprintf("url:%s req: %+v", variable.Config.Services.GetGlm2GuideResult, req))
	resByte, err := w.HttpClient(req, variable.Config.Services.GetGlm2GuideResult, "POST")
	if err != nil {
		return nil, err
	}
	log.Logger.Info(fmt.Sprintf("resByte: %+v", resByte))
	type res struct {
		Data string `json:"data"`
	}
	var resStruct res
	_ = json.Unmarshal(resByte, &resStruct)
	return resStruct.Data, nil
}

func (w *DefaultWebReport) GetGuideData() (interface{}, error) {
	guide := &Guide{
		MajorPromotion:        "",
		ProjectExpression:     "",
		AccomplishmentDisplay: "",
		MajorPromotionScore:   int(w.evaluateResp.LabelScore.Profession * 100),
		UniversalAbilityScore: int(w.evaluateResp.LabelScore.General * 100),
	}
	careerId := strconv.Itoa(int(w.Session.CareerID))
	//proScore := w.evaluateResp.LabelScore.Profession * 100
	//switch {
	//case proScore > 75:
	//	guide.MajorPromotion = SuggestComments[careerId]["专业能力提升"]["A"]
	//case proScore >= 50:
	//	guide.MajorPromotion = SuggestComments[careerId]["专业能力提升"]["B"]
	//case proScore >= 25:
	//	guide.MajorPromotion = SuggestComments[careerId]["专业能力提升"]["C"]
	//case proScore >= 0:
	//	guide.MajorPromotion = SuggestComments[careerId]["专业能力提升"]["D"]
	//}
	experienceGoodLabelLen := len(w.evaluateResp.PosWordScore.Experience)
	switch {
	case experienceGoodLabelLen >= 4:
		guide.ProjectExpression = SuggestComments[careerId]["项目经验表述"]["A"]
	case experienceGoodLabelLen >= 2:
		guide.ProjectExpression = SuggestComments[careerId]["项目经验表述"]["B"]
	case experienceGoodLabelLen == 1:
		guide.ProjectExpression = SuggestComments[careerId]["项目经验表述"]["C"]
	case experienceGoodLabelLen == 0:
		guide.ProjectExpression = SuggestComments[careerId]["项目经验表述"]["D"]
	}
	generalScore := w.evaluateResp.LabelScore.General * 100
	switch {
	case generalScore >= 75:
		guide.AccomplishmentDisplay = SuggestComments[careerId]["个人素养展现"]["A"]
	case generalScore >= 50:
		guide.AccomplishmentDisplay = SuggestComments[careerId]["个人素养展现"]["B"]
	case generalScore >= 25:
		guide.AccomplishmentDisplay = SuggestComments[careerId]["个人素养展现"]["C"]
	case generalScore >= 0:
		guide.AccomplishmentDisplay = SuggestComments[careerId]["个人素养展现"]["D"]
	}
	glm2Guide, err := w.GetGlm2Guide()
	if err != nil {
		return nil, err
	}
	guide.Glm2Suggest = glm2Guide
	guide.MajorPromotion = glm2Guide.(string)
	return guide, nil
}

func (w *DefaultWebReport) GetVocationalData() (interface{}, error) {
	professional := w.GetProfessionalData()
	generalData := w.IWebReport.GetGeneralData()
	instrumentalData := w.GetInstrumentalData()
	experienceData := w.GetExperienceData()
	personalData := w.GetPersonalData()
	occupationMapData := w.GetOccupationMapData(professional, generalData)
	labelValue := []LabelValue{}
	return &ProfessionalData{
		Professional:      professional,
		GeneralPurpose:    generalData,
		InstrumentalSkill: instrumentalData,
		PersonalTrait:     personalData,
		Experience:        experienceData,
		OtherBrightSpot:   labelValue,
		OccupationMap:     occupationMapData,
	}, nil
}

func (w *DefaultWebReport) GetInterviewScore() (int, error) { // 获取面试总分
	var (
		total, totalLanguageScore, totalThemeScore, totalExpressiveScore float64
		quesLen                                                          = float64(len(w.RealQues))
	)
	allCache := []*scoreCache{
		&w.fluencyChartCache,
		&w.asrCache,
		&w.moodCache,
		&w.toneCache,
		&w.logicScoreCache,
		&w.performanceScoreCache,
	}
	for _, cache := range allCache {
		cache.Scores = make([]float64, 0)
	}
	w.personalityScore = make(map[string]float64)
	labelCacheList := make([]interface{}, 0)
	analyzeLabelsList := make([]string, 0)
	for _, q := range w.RealQues {
		totalLanguageScore += q.LanguageScore
		totalThemeScore += q.ThemeScore
		totalExpressiveScore += q.ExpressScore
		w.allAnswerContent += q.AnswerText
		w.fluencyChartCache.Scores = append(w.fluencyChartCache.Scores, q.LanguageFluencyScore)
		w.asrCache.Scores = append(w.asrCache.Scores, q.AsrScore)
		w.moodCache.Scores = append(w.moodCache.Scores, q.Mood)
		w.toneCache.Scores = append(w.toneCache.Scores, q.Tone)
		w.logicScoreCache.Scores = append(w.logicScoreCache.Scores, q.LogicScore)
		w.performanceScoreCache.Scores = append(w.performanceScoreCache.Scores, q.PerformanceScore)
		if q.Cr != nil {
			for _, character := range q.Cr.Personality {
				w.personalityScore[character.Title] += character.Score
			}
		}
		// 将缓存起来的标签词评测中间结果合并起来，用于最终的标签词获取
		var partLabelCache interface{}
		_ = json.Unmarshal([]byte(q.PartLabelsCache), &partLabelCache)
		if partLabelCache != nil {
			labelCacheList = append(labelCacheList, partLabelCache)
		}
		// 题目解析里涉及到的标签词，会影响neg_wow_score_dict的结果
		analyzeLabels := make([]string, 0)
		_ = json.Unmarshal([]byte(q.Question.KeyWords), &analyzeLabels)
		analyzeLabelsList = append(analyzeLabelsList, analyzeLabels...)
		if len(analyzeLabels) > 0 {
			w.analyzeLabelsList = append(w.analyzeLabelsList, analyzeLabels[0])
		}
	}
	for k, v := range w.personalityScore {
		if quesLen == 0 {
			w.personalityScore[k] = 0
		} else {
			w.personalityScore[k] = v * 100 / quesLen
		}
	}
	if quesLen == 0 {
		w.avgLanguageScore = 0
		w.avgThemeScore = 0
		w.avgExpressiveScore = 0
	} else {
		w.avgLanguageScore = totalLanguageScore / quesLen
		w.avgThemeScore = totalThemeScore / quesLen
		w.avgExpressiveScore = totalExpressiveScore / quesLen
	}
	reqStruct := map[string]interface{}{
		"job_name":           w.Session.Career.Name,
		"label_extract_list": labelCacheList,
		"analyze_labels":     analyzeLabelsList,
	}
	reqData, _ := json.Marshal(reqStruct)
	w.evaluateResp = FetchEvaluationScore(reqData)
	for _, cache := range allCache {
		cache.Variance, cache.Avg = CalculateStandardVariance(cache.Scores)
	}
	total = w.IWebReport.GetTotalScore()
	w.Session.TotalScore = total
	jsonData, _ := json.Marshal(w.evaluateResp)
	w.Session.Evaluation = string(jsonData)
	if err := variable.DB.MySQL.Model(w.Session).Select("TotalScore", "Evaluation").
		Updates(w.Session).Error; err != nil {
		return 0, err
	}
	return int(total), nil
}

func (w *DefaultWebReport) SetCharacterData(q *tables.RealQues) error {
	cr, err := FetchCharacter(q.AnswerText)
	if err != nil {
		return err
	}
	q.Cr = &cr
	return nil
}

func (w *DefaultWebReport) GetPersonalityData() (interface{}, error) {
	chartData := make([]*ChartData, 0)
	for k, v := range w.personalityScore {
		chartData = append(chartData, &ChartData{
			Title: k,
			Score: int(v),
		})
	}

	insight := make([]string, 0)
	insight = append(insight, "综合分析您在面试回答中所呈现出的人格特征，显示你在工作的过程中：")
	insightSort := []string{"开放性", "严谨性", "外向性", "宜人性", "神经质"}
	for _, label := range insightSort {
		var trick string
		score := w.personalityScore[label]
		switch {
		case score >= 70:
			trick = AbilityComments["ocean"][label]["A"]
		case score >= 30:
			trick = AbilityComments["ocean"][label]["B"]
		default:
			trick = AbilityComments["ocean"][label]["C"]
		}
		insight = append(insight, trick)
	}
	personalityRecord := make([]*tables.Personality, 0)
	if err := variable.DB.MySQL.Find(&personalityRecord).Error; err != nil {
		return nil, err
	}

	workMode := make([]*WorkMode, 0)
	for _, record := range personalityRecord {
		score := w.personalityScore[record.Name]
		if score > record.MaxLevel || score < record.MinLevel {
			continue
		}
		workMode = append(workMode, &WorkMode{
			Name:    record.WorkMethod,
			Source1: record.FiveCharacter,
			Source2: record.Type,
		})
	}
	return &Personality{
		ChartData: chartData,
		Insight:   insight,
		WorkMode:  workMode,
	}, nil
}

func (w *DefaultWebReport) GetScoreOverView() (interface{}, error) {
	pro := int(w.evaluateResp.LabelScore.Profession * 100)
	gen := int(w.evaluateResp.LabelScore.General * 100)
	return &ScoreOverView{
		ProfessionalQuality: (pro + gen) / 2,
		ExpressiveScore:     int(w.avgExpressiveScore),
		EmphasisScore:       int(w.avgThemeScore),
		LogicScore:          int(w.logicScoreCache.Avg),
	}, nil
}
